import struct
from global_settings import debug_print


class ProtocolParser:
    def __init__(self):
        self.device_address = 0x01
        self.last_request_info = {}  # 记录最后一次请求信息

    def set_device_address(self, address):
        """设置设备地址"""
        self.device_address = address

    def parse_response(self, data, start_address=0, register_count=1):
        """解析Modbus响应数据 - 增强版本"""
        result = {}

        if not data or len(data) < 5:
            debug_print(f"响应数据长度不足: {len(data) if data else 0}")
            return result

        try:
            # 检查设备地址
            if data[0] != self.device_address:
                debug_print(f"设备地址不匹配: 期望{self.device_address}, 收到{data[0]}")
                return result

            function_code = data[1]
            debug_print(f"功能码: 0x{function_code:02X}")

            # 检查异常响应
            if function_code & 0x80:
                error_code = data[2]
                error_messages = {
                    0x01: "非法功能码",
                    0x02: "非法数据地址",
                    0x03: "非法数据值",
                    0x04: "从站设备故障",
                    0x05: "确认",
                    0x06: "从站设备忙",
                    0x08: "存储奇偶性错误",
                    0x0A: "网关路径不可用",
                    0x0B: "网关目标设备响应失败"
                }
                error_msg = error_messages.get(error_code, f"未知错误码 {error_code}")
                debug_print(f"Modbus异常响应: {error_msg}")
                result["error"] = error_msg
                return result

            if function_code == 0x03:  # 读取保持寄存器
                byte_count = data[2]
                expected_byte_count = register_count * 2

                if byte_count != expected_byte_count:
                    debug_print(f"数据长度不匹配: 期望{expected_byte_count}, 收到{byte_count}")
                    # 仍然尝试解析可用的数据
                    available_registers = min(byte_count // 2, register_count)
                else:
                    available_registers = register_count

                debug_print(f"解析 {available_registers} 个寄存器, 字节数: {byte_count}")
                # 解析寄存器数据
                for i in range(available_registers):
                    if 3 + i * 2 + 1 < len(data):
                        value = (data[3 + i * 2] << 8) | data[3 + i * 2 + 1]
                        address = start_address + i

                        result[str(address)] = value
                        debug_print(f"解析寄存器: 地址={address}(0x{address:04X}), 原始值={value}(0x{value:04X})")

            elif function_code == 0x06:  # 写入单个寄存器
                address = (data[2] << 8) | data[3]
                value = (data[4] << 8) | data[5]
                result[str(address)] = value
                result["write_success"] = True
                debug_print(f"写入成功: 地址={address}(0x{address:04X}), 值={value}")

            elif function_code == 0x10:  # 写入多个寄存器
                address = (data[2] << 8) | data[3]
                count = (data[4] << 8) | data[5]
                result["start_address"] = address
                result["register_count"] = count
                result["write_success"] = True
                debug_print(f"批量写入成功: 起始地址={address}, 数量={count}")

            else:
                debug_print(f"不支持的功能码: {function_code}")

        except Exception as e:
            debug_print(f"解析响应数据错误: {str(e)}")
            debug_print(f"原始数据: {self._bytes_to_hex(data)}")

        return result

    def _bytes_to_hex(self, data):
        """将字节数据转换为十六进制字符串"""
        return ' '.join(f'{byte:02X}' for byte in data)

    def format_read_command(self, start_address, register_count):
        """格式化读取命令"""
        command = bytearray()
        command.append(self.device_address)
        command.append(0x03)  # 功能码: 读取保持寄存器
        command.append((start_address >> 8) & 0xFF)
        command.append(start_address & 0xFF)
        command.append((register_count >> 8) & 0xFF)
        command.append(register_count & 0xFF)

        crc = self._calculate_crc(command)
        command.append(crc & 0xFF)
        command.append((crc >> 8) & 0xFF)

        self.last_request_info = {
            'start_address': start_address,
            'register_count': register_count
        }

        return command

    def format_write_command(self, address, value):
        """格式化写入命令"""
        command = bytearray()
        command.append(self.device_address)
        command.append(0x06)  # 功能码: 写入单个寄存器
        command.append((address >> 8) & 0xFF)
        command.append(address & 0xFF)
        command.append((value >> 8) & 0xFF)
        command.append(value & 0xFF)

        crc = self._calculate_crc(command)
        command.append(crc & 0xFF)
        command.append((crc >> 8) & 0xFF)

        return command

    def _calculate_crc(self, data):
        """计算Modbus CRC16校验码"""
        crc = 0xFFFF
        for pos in data:
            crc ^= pos
            for i in range(8):
                if (crc & 1) != 0:
                    crc >>= 1
                    crc ^= 0xA001
                else:
                    crc >>= 1
        return crc

    def parse_register_value(self, raw_value, data_type="uint16", scale=1):
        """解析寄存器值 - 增强版本，支持有符号数处理和两位小数"""
        try:
            if data_type == "uint16":
                value = int(raw_value) * scale
                # 如果缩放因子是小数，返回浮点数并保留两位小数
                if isinstance(scale, float):
                    return round(float(value), 2)
                return value

            elif data_type == "int16":
                # 处理有符号16位整数
                value = int(raw_value)
                # 如果值大于32767，说明是负数（补码表示）
                if value > 32767:
                    value = value - 65536  # 转换为有符号整数
                result = value * scale
                # 如果缩放因子是小数，返回浮点数并保留两位小数
                if isinstance(scale, float):
                    return round(float(result), 2)
                return result

            elif data_type == "float":
                # 浮点数直接保留两位小数
                return round(float(raw_value) * scale, 2)

            else:
                result = raw_value * scale
                # 如果缩放因子是小数，返回浮点数并保留两位小数
                if isinstance(scale, float):
                    return round(float(result), 2)
                return result

        except (ValueError, TypeError) as e:
            debug_print(f"解析寄存器值失败: raw_value={raw_value}, data_type={data_type}, scale={scale}, 错误: {e}")
            # 错误情况下也尝试保留两位小数
            try:
                if isinstance(scale, float):
                    return round(float(raw_value * scale), 2)
                return raw_value * scale
            except:
                return raw_value * scale